package cvgenerator.web;

import cvgenerator.backend.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Random;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.DontValidate;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.StreamingResolution;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrors;

/**
 * Class resposible for transforming and generating CVs, checking errors and manipulating the form.
 * @author Jan Mjartan.
 */
public class CvCreateAction implements ActionBean {

    public static final String FORMJSP = "/form.jsp";
    public static final int IDRANGE = 1000000;
    public static final String INDEXJSP = "/index.jsp";
    public static final String NOSCHOOLERROR = "cvgenerator.web.CvCreateAction.noschools";
    public static final String NOWORKERROR = "cvgenerator.web.CvCreateAction.nowork";
    public static final String NOINTERESTERROR = "cvgenerator.web.CvCreateAction.nointerests";
    public static final String NOLANGERROR = "cvgenerator.web.CvCreateAction.nolanguages";
    public static final String NOSKILLERROR = "cvgenerator.web.CvCreateAction.noskills";
    public static final String CVGENHOME = "CVGENHOME";
    
    private ActionBeanContext context;
    private final String homeFolder;
    
    @ValidateNestedProperties({
        @Validate(field = "name", required = true),
        @Validate(field = "phone", required = true),
        @Validate(field = "email", required = true, mask = ".+@.+\\..+"),
        @Validate(field = "bDay", required = true),
        @Validate(field = "address.street", required = true),
        @Validate(field = "address.streetNumber", required = true),
        @Validate(field = "address.postNumber", required = true),
        @Validate(field = "address.city", required = true),
        @Validate(field = "address.country", required = true),
        @Validate(field = "workExperience.from", required = true),
        @Validate(field = "workExperience.to", required = true),
        @Validate(field = "workExperience.company", required = true),
        @Validate(field = "workExperience.position", required = true),
        @Validate(field = "schools.from", required = true),
        @Validate(field = "schools.to", required = true),
        @Validate(field = "schools.name", required = true),
        @Validate(field = "languages.name", required = true),
        @Validate(field = "languages.level", required = true)})
    private Cv cv;
    
    public CvCreateAction() {
        homeFolder = getHomeFolder();
    }
    
    @Override
    public void setContext(ActionBeanContext context) {
        this.context = context;
    }

    @Override
    public ActionBeanContext getContext() {
        return context;
    }

    public Cv getCv() {
        return cv;
    }

    public void setCv(Cv cv) {
        this.cv = cv;
    }

    /**
     * Creates this page
     * @return Resolution containg the CV form
     */
    @DefaultHandler
    @DontValidate
    public Resolution create() {      
        String cvId = getContext().getRequest().getParameter("cvId");
        File cvFile;
        if (cvId == null) {
            return new ForwardResolution(INDEXJSP);
        }
        
        if ("new".equals(cvId)) {
            cv = new Cv();
            do {
                long newId = new Random().nextInt(IDRANGE);
                cv.setId(newId);
                cvFile = getFile(newId, "xml");
            } while (cvFile.exists());
        } else {
            try {
                cvFile = getFile(Integer.valueOf(cvId), "xml");
                if(!cvFile.exists()) {
                    return new ForwardResolution(INDEXJSP);
                }
                cv = Cv.loadFromFile(cvFile);
            } catch (Exception e) {
                return new ForwardResolution(INDEXJSP);
            } 
        }
        return new ForwardResolution(FORMJSP);
    }

    /**
     * Saves CV to a xml and transforms it to tex.
     * 
     * @return Resolution containing CV form with check errors
     */
    public Resolution saveCV() throws TransformerException, URISyntaxException {
        ValidationErrors errors = new ValidationErrors();
        if (cv.getSchools().isEmpty()) {
            errors.add("cv.schools[0].name", new LocalizableError(NOSCHOOLERROR));
        }
        if (cv.getWorkExperience().isEmpty()) {
            errors.add("cv.workExperience[0].company", new LocalizableError(NOWORKERROR));
        }
        if (cv.getInterests().isEmpty()) {
            errors.add("cv.interests[0]", new LocalizableError(NOINTERESTERROR));
        }
        if (cv.getLanguages().isEmpty()) {
            errors.add("cv.languages[0].name", new LocalizableError(NOLANGERROR));
        }
        if (cv.getSkills().isEmpty()) {
            errors.add("cv.skills[0]", new LocalizableError(NOSKILLERROR));
        }
        getContext().setValidationErrors(errors);
        if (!errors.isEmpty()) {
            return new ForwardResolution("/form.jsp");
        }
        cv.saveToFile(getFile(cv.getId(), "xml"));
        TransformerFactory factory = TransformerFactory.newInstance();
        Source xslt = new StreamSource(getClass().getResourceAsStream("/cvTransformation.xsl"));        
        Transformer transformer = factory.newTransformer(xslt);
        Source input = new StreamSource(getFile(cv.getId() , "xml"));
        transformer.transform(input, new StreamResult(getFile(cv.getId(), "tex")));
        return new ForwardResolution(FORMJSP);
    }

    /**
     * Compiles latex style to a PDF.
     * @return Returns a Resoltion containing PDF.
     */
    public Resolution downloadCV() throws InterruptedException {
        try {
            String cmd = "cmd /c pdflatex " + homeFolder + cv.getId() + ".tex -output-directory " + homeFolder + " > "  + homeFolder + "log.txt";
            System.out.println(cmd);
            Process shell = Runtime.getRuntime().exec(cmd);
            shell.waitFor();
            InputStream is = new FileInputStream(getFile(cv.getId(), "pdf"));
            return new StreamingResolution("application/pdf", is);
        } catch (IOException e) {
            return new ForwardResolution(FORMJSP);
        }
    }

    private File getFile(long cvId, String extension) {
        return new File(homeFolder + cvId + "." + extension);
    }
    
    private String getHomeFolder() {
        String homeFolder = System.getenv(CVGENHOME);
        if (homeFolder.charAt(homeFolder.length() - 1) != '/' && homeFolder.charAt(homeFolder.length() - 1) != '\\') {
            homeFolder = homeFolder + '\\';
        }
        return homeFolder;
    }
    
}
